package com.yz.test.parking.http;


import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.lang.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Data
public class HttpClientManager {
    private static MultiThreadedHttpConnectionManager connectionManager = null;
    private static HttpClientManager instance = new HttpClientManager();

    public static HttpClientManager getInstance() {
        return instance;
    }

    private int maxThreadsTotal = 128;

    private int maxThreadsPerHost = 32;

    private int connectionTimeout = 10000;

    private int soTimeout = 60000;

    private HttpClientManager() {
        init();
    }

    public void init() {
        connectionManager = new MultiThreadedHttpConnectionManager();
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        params.setConnectionTimeout(connectionTimeout);
        params.setMaxTotalConnections(maxThreadsTotal);
        params.setSoTimeout(soTimeout);
        if (maxThreadsTotal > maxThreadsPerHost) {
            params.setDefaultMaxConnectionsPerHost(maxThreadsPerHost);
        } else {
            params.setDefaultMaxConnectionsPerHost(maxThreadsTotal);
        }
        connectionManager.setParams(params);
    }

    public HttpRequestResult requestDataByUrl(String url, RequestTypeEnum type,
                                              EncodeEnum encode, Map<String, String> parmMap) {
        if (StringUtils.isNotBlank(url) && type != null) {
            log.debug("http url:"+url+",type:"+type.name()+",params:"+parmMap);
            if (type == RequestTypeEnum.POST) {
                return requestDataByPost(url, encode, parmMap);
            } else {
                return requestDataByGet(url, encode, parmMap);
            }
        } else {
            log.warn("send url or type can not null");
            return new HttpRequestResult(HttpRequestStatusCodeEnum.BAD_REQUEST,
                    false, null);
        }
    }

    private HttpRequestResult requestDataByGet(String url, EncodeEnum encode,
                                               Map<String, String> parmMap) {
        HttpClient httpClient = new HttpClient(connectionManager);
        httpClient.getHttpConnectionManager().getParams()
                .setConnectionTimeout(connectionTimeout);
        httpClient.getHttpConnectionManager().getParams()
                .setSoTimeout(soTimeout);
        String sendUrl = RequestDataManager.getSendUrl(url, parmMap);
        GetMethod getMethod = new GetMethod(sendUrl);
        getMethod.getParams().setContentCharset(encode.getEncode());
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 10000);
        int statusCode = 0;
        try {
            statusCode = httpClient.executeMethod(getMethod);
            if (statusCode != HttpStatus.SC_OK) {
                return new HttpRequestResult(
                        HttpRequestStatusCodeEnum.valueOf(statusCode), false,
                        null);
            }
            InputStream resStream = getMethod.getResponseBodyAsStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(resStream,encode.getEncode()));
            StringBuffer resBuffer = new StringBuffer();
            String res = "";
            while((res = br.readLine()) != null){
                resBuffer.append(res);
            }
            String resultReturn = resBuffer.toString();
            return new HttpRequestResult(
                    HttpRequestStatusCodeEnum.valueOf(statusCode), true,
                    resultReturn);
        } catch (HttpException e) {
            log.error("send url:" + url, e);
            return new HttpRequestResult(HttpRequestStatusCodeEnum.BAD_REQUEST,
                    false, e.getMessage());
        } catch (IOException e) {
            log.error("send url:" + url, e);
            return new HttpRequestResult(HttpRequestStatusCodeEnum.BAD_REQUEST,
                    false, e.getMessage());
        } finally {
            getMethod.releaseConnection();
        }
    }


    private HttpRequestResult requestDataByPost (String url,
                                                 EncodeEnum encode, Map<String, String> parmMap) {
        HttpClient httpClient = new HttpClient(connectionManager);
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(
                connectionTimeout);
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(
                soTimeout);
        PostMethod postMethod = new  PostMethod(url);
        postMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,10000);
        postMethod.getParams().setParameter(HttpMethodParams.HTTP_ELEMENT_CHARSET,encode.getEncode());
        postMethod.getParams().setContentCharset(encode.getEncode());
        if (parmMap != null) {
            NameValuePair[] params = new NameValuePair[parmMap.size()];
            AtomicInteger atomicInteger = new AtomicInteger(0);
            for (Map.Entry<String, String> parm : parmMap.entrySet()) {
                NameValuePair parmValue;
                parmValue = new NameValuePair(parm.getKey(),String.valueOf(parm.getValue()));
                params[atomicInteger.getAndIncrement()] = parmValue;
            }
            postMethod.setRequestBody(params);
        }
        try {
            int statusCode = httpClient.executeMethod(postMethod);
            if (statusCode != HttpStatus.SC_OK) {
                return new HttpRequestResult(HttpRequestStatusCodeEnum
                        .valueOf(statusCode), false, null);
            }
            InputStream resStream = postMethod.getResponseBodyAsStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(resStream,encode.getEncode()));
            StringBuffer resBuffer = new StringBuffer();
            String res = "";
            while((res = br.readLine()) != null){
                resBuffer.append(res);
            }
            String resultReturn = resBuffer.toString();
            return new HttpRequestResult(HttpRequestStatusCodeEnum
                    .valueOf(statusCode), true, resultReturn);
        } catch (HttpException e) {
            log.error("send url:" + url, e);
            return new HttpRequestResult(
                    HttpRequestStatusCodeEnum.BAD_REQUEST, false, e.getMessage());
        } catch (IOException e) {
            log.error("send url:" + url, e);
            return new HttpRequestResult(
                    HttpRequestStatusCodeEnum.BAD_REQUEST, false, e.getMessage());
        } finally {
            postMethod.releaseConnection();
        }
    }


    /**
     * @Description:  忽略证书的http post 请求
     * @param strURL
     * @param parmMap
     * @return boolean
     * @Date 2015年8月5日 下午3:40:05
     * @auther zhangyi
     */
    public HttpRequestResult executePostMethodIngoreCert(String strURL, Map<String, String> parmMap) {
        if (strURL == null || strURL.length() <= 0) {
            throw new RuntimeException("请求路径不能为空");
        }
        HttpClient httpClient = new HttpClient(connectionManager);
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(
                connectionTimeout);
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(
                soTimeout);
        PostMethod post = new PostMethod(strURL);
        try {
            post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
            post.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,10000);
            post.getParams().setParameter(HttpMethodParams.HTTP_ELEMENT_CHARSET,EncodeEnum.UTF8.getEncode());
            if (parmMap != null) {
                NameValuePair[] params = new NameValuePair[parmMap.size()];
                AtomicInteger atomicInteger = new AtomicInteger(0);
                for (Map.Entry<String, String> parm : parmMap.entrySet()) {
                    NameValuePair parmValue;
                    parmValue = new NameValuePair(parm.getKey(),String.valueOf(parm.getValue()));
                    params[atomicInteger.getAndIncrement()] = parmValue;
                }
                post.setRequestBody(params);
            }
            Protocol myhttps = new Protocol("https", new SimpleSSLProtocolSocketFactory(), 443);
            Protocol.registerProtocol("https", myhttps);
            int statusCode = httpClient.executeMethod(post);
            if (statusCode != HttpStatus.SC_OK) {
                return new HttpRequestResult(HttpRequestStatusCodeEnum
                        .valueOf(statusCode), false, null);
            }
            InputStream resStream = post.getResponseBodyAsStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(resStream,EncodeEnum.UTF8.getEncode()));
            StringBuffer resBuffer = new StringBuffer();
            String res = "";
            while((res = br.readLine()) != null){
                resBuffer.append(res);
            }
            String resultReturn = resBuffer.toString();
            return new HttpRequestResult(HttpRequestStatusCodeEnum
                    .valueOf(statusCode), true, resultReturn);
        } catch (HttpException e) {
            log.error("send url:" + strURL, e);
            return new HttpRequestResult(
                    HttpRequestStatusCodeEnum.BAD_REQUEST, false, e.getMessage());
        } catch (IOException e) {
            log.error("send url:" + strURL, e);
            return new HttpRequestResult(
                    HttpRequestStatusCodeEnum.BAD_REQUEST, false, e.getMessage());
        } finally {
            post.releaseConnection();
        }
    }


//    public static HttpClientTools getHttpClientTools(){
//        return new HttpClientTools(connectionManager);
//    }

}
